//
// JTBlockStencilToken
//
// Copyright (C) jextra.net.
//
//  This file is part of the JavaTemplar Library.
//
//  The JavaTemplar Library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  The JavaTemplar Library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with the JavaTemplar Library; if not, write to the Free
//  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
//  02111-1307 USA.
//

package net.jextra.javatemplar.token;

import java.io.*;
import java.util.*;

/**
 * <p>
 * A section of the template file that has been group together and contains child tokens.
 * </p><p>
 * This usually represents the tokens between a "begin" tag and and "end" tag:
 * </p>
 * <pre>
 *     ${begin myBlock}
 *     This is the value of the variable name: ${name} with the myBlock.
 *     ${end myBlock}
 * </pre>
 */
public class JTBlockStencilToken implements JTToken
{
    // ============================================================
    // Fields
    // ============================================================

    private JTBlockStencilToken _parent;
    private String _name;
    private ArrayList<JTToken> _tokens;
    private ArrayList<JTBlock> _blocks;

    // ============================================================
    // Constructors
    // ============================================================

    public JTBlockStencilToken( JTBlockStencilToken parent, String name )
    {
        _parent = parent;
        _name = name;
        _tokens = new ArrayList<JTToken>();
        _blocks = new ArrayList<JTBlock>();
    }

    // ============================================================
    // Methods
    // ============================================================

    // ----------
    // public
    // ----------

    @Override
    public JTBlockStencilToken clone()
    {
        JTBlockStencilToken copy = new JTBlockStencilToken( _parent, _name );

        // Copy all of the children to the new clone.
        for ( JTToken token : _tokens )
        {
            copy.addToken( token.clone() );
        }

        // Copy all of the blocks to new clone.
        for ( JTBlock block : _blocks )
        {
            copy._blocks.add( block.clone() );
        }

        return copy;
    }

    /**
     * This is the name from the begin tag:
     * <pre>
     *      ${begin name}
     * </pre>
     */
    public String getName()
    {
        return _name;
    }

    public void setName( String name )
    {
        _name = name;
    }

    /**
     * Since blocks can be contained within other blocks, this allows for inheritance traversing.
     */
    public JTBlockStencilToken getParent()
    {
        return _parent;
    }

    public void setParent( JTBlockStencilToken parent )
    {
        _parent = parent;
    }

    /**
     * Add a child token to this block.
     */
    public void addToken( JTToken token )
    {
        _tokens.add( token );
    }

    public List<JTToken> getTokens()
    {
        return _tokens;
    }

    /**
     * A Stencil does not write itself but writes all of its {@link JTBlock}s instead.
     */
    public void write( Writer out )
        throws Exception
    {
        for ( JTBlock block : _blocks )
        {
            block.write( out );
        }
    }

    /**
     * Sets the value associated with any variables with the given name the value. Note, this
     * is a recursive call. It also calls setVariable on the last "active" {@link JTBlock}s.
     */
    public JTBlock setVariable( String variableName, String value )
    {
        //
        // Propogate through the children.
        //
        for ( JTToken token : _tokens )
        {
            if ( token instanceof JTBlockStencilToken )
            {
                JTBlockStencilToken stencil = (JTBlockStencilToken)token;

                stencil.setVariable( variableName, value );
            }
            else if ( token instanceof JTVariableToken )
            {
                JTVariableToken var = (JTVariableToken)token;

                if ( variableName.equals( var.getName() ) )
                {
                    var.setValue( value );
                }
            }
        }

        //
        // Set variable only on the last "active" block.
        //
        if ( !_blocks.isEmpty() )
        {
            _blocks.get( _blocks.size() - 1 ).setVariable( variableName, value );
        }

        return null;
    }

    /**
     * If this stencil has the given block name then make a block of it. Also recurse through
     * children for other stencils with given name.
     */
    public boolean makeBlock( String blockName )
    {
        boolean found = false;

        // If this stencil has the given name, make a block for this stencil
        if ( getName().equals( blockName ) )
        {
            makeBlock();
            found = true;
        }

        //
        // Recurse through active block.
        //
        if ( !_blocks.isEmpty() )
        {
            JTBlock block = _blocks.get( _blocks.size() - 1 );

            for ( JTToken token : block.getTokens() )
            {
                if ( makeBlock( token, blockName ) )
                {
                    found = true;
                }
            }
        }

        return found;
    }

    /**
     * Create a new block for this stencil.
     */
    public void makeBlock()
    {
        JTBlock block = new JTBlock();
        for ( JTToken token : _tokens )
        {
            block.addToken( token.clone() );
        }

        _blocks.add( block );
    }
    
    // ----------
    // protected
    // ----------

    protected boolean makeBlock( JTToken token, String blockName )
    {
        boolean found = false;

        if ( token instanceof JTBlockStencilToken )
        {
            JTBlockStencilToken stencil = (JTBlockStencilToken)token;

            if ( stencil.makeBlock( blockName ) )
            {
                found = true;
            }
        }

        return found;
    }
}

